using System;
using System.Linq;
using System.Custom;
using CustomControls;
using System.Xml.Linq;
using CoreTypes.Properties;
using System.Custom.Window;
using System.Globalization;
using System.Windows.Forms;
using System.ComponentModel;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace CoreTypes
{
   public class SessionVisualizer : UserControl, ISessionVisualizer
   {
      #region SessionVisualizer Data

      Type FSessionType;
      protected MediaSession FSession;
      protected IBaseCommunicator FCommunicator;
      protected ComponentResourceManager FResources;
      protected Panel panelStartPage;
      protected Panel panelMainPage;
      private static ColorTheme FColorTheme;

      #endregion

      #region ISessionVisualizer Initializers

      private void InitializeComponent()
      {
         System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SessionVisualizer));
         this.panelStartPage = new System.Windows.Forms.Panel();
         this.panelMainPage = new System.Windows.Forms.Panel();
         this.SuspendLayout();
         // 
         // panelStartPage
         // 
         this.panelStartPage.BackColor = System.Drawing.Color.WhiteSmoke;
         resources.ApplyResources(this.panelStartPage, "panelStartPage");
         this.panelStartPage.MinimumSize = new System.Drawing.Size(480, 380);
         this.panelStartPage.Name = "panelStartPage";
         // 
         // panelMainPage
         // 
         this.panelMainPage.BackColor = System.Drawing.Color.GhostWhite;
         resources.ApplyResources(this.panelMainPage, "panelMainPage");
         this.panelMainPage.Name = "panelMainPage";
         // 
         // SessionVisualizer
         // 
         this.Controls.Add(this.panelMainPage);
         this.Controls.Add(this.panelStartPage);
         resources.ApplyResources(this, "$this");
         this.Name = "SessionVisualizer";
         this.ResumeLayout(false);

      }

      protected SessionVisualizer()
      {
         // Do not remove this constructor, Visual Designer uses it.
         InitializeComponent();
      }
      public SessionVisualizer(IBaseCommunicator communicator)
      {
         InitializeComponent();

         FCommunicator = communicator;

         panelMainPage.BringToFront();
      }

      #endregion

      #region IVisualRegion Members

      public void Conceal()
      {
         Hide();
      }
      public bool IsVisible
      {
         get { return Visible; }
      }
      public virtual void Visualize()
      {
         SuspendLayout();
         Parent.SuspendLayout();

         if (Session != null)
         {
            switch (Session.State)
            {
               case SessionState.Ready:
               case SessionState.Waiting:
               case SessionState.Sending:
               case SessionState.Establishing:
               {
                  ShowMainPage();
                  break;
               }
               case SessionState.Closed:
               {
                  ShowStartPage(true);
                  break;
               }
            }
         }
         else ShowStartPage(true);

         BringToFront();
         Visible = true;

         Parent.ResumeLayout();
         ResumeLayout();

         Refresh();
      }

      public ColorTheme ColorTheme
      {
         get
         {
            return FColorTheme;
         }
         set
         {
            FColorTheme = value;
            Refresh();
         }
      }
      public ToolStripRenderMode RenderMode
      {
         get
         {
            return ToolStripRenderMode.Custom;
         }
         set
         {
            //
         }
      }

      #endregion

      #region ISessionVisualizer Members

      public bool ParamsEnabled
      {
         get
         {
            return true;
         }
         set
         {
         }
      }
      public IMediaWindow MediaWindow
      {
         get
         {
            return FindForm() as IMediaWindow;
         }
         set
         {
            if (value == null)
            {
               MediaWindow.DetachSession(Session);
            }
            else
            {
               MediaWindow.AttachSession(Session);
            }
         }
      }

      public virtual IMediaSession Session
      {
         get
         {
            return FSession;
         }
         set
         {
            if (FSession == value) return;

            FSession = value as MediaSession;

            if (FSession != null) FSessionType = FSession.GetType();

            RefreshView();
         }
      }
      public virtual string SessionCaption
      {
         get
         {
            return Resources.S_New + " " + SessionFullTypeTag;
         }
         set
         {
            //
         }
      }
      public virtual string SessionSubject
      {
         get
         {
            return "";
         }
         set
         {
            //
         }
      }
      public virtual string SessionTypeTag
      {
         get
         {
            return GetType().Name.SubstrBefore("Session");
         }
      }
      public virtual string SessionDescription
      {
         get
         {
            return "";// labelSessionDesc.Text == "" ? SessionFullTypeTag : labelSessionDesc.Text;
         }
         set
         {
            //labelSessionDesc.Text = value;
         }
      }
      public virtual string SessionFullTypeTag
      {
         get
         {
            return SessionTypeTag + " " + SessionSubtype.ToString() + (SessionSubtype == SessionSubtype.Personal ? " " + Resources.S_Session.ToLower() : "");
         }
      }
      public virtual string SessionInvitationText
      {
         get
         {
            return "";// editSessionInvitationText.Text;
         }
         set
         {
            //editSessionInvitationText.Text = value == null ? "I invite you to " + (SessionSubtype == SessionSubtype.Translation ? "view" : "participate in") + " my " + SessionFullTypeTag + ". Please welcome!" : value;
            //editSessionInvitationText.Text = value;
         }
      }

      public Type SessionType
      {
         get
         {
            return FSessionType;
         }
         set
         {
            if (FSession == null) FSessionType = value;
         }
      }
      public string SessionHost
      {
         get
         {
            return "";// editSessionMachine.Text;
         }
         set
         {
            //editSessionMachine.Text = value;
         }
      }
      public int SessionIdleTimeout
      {
         get
         {
            return 0;// return decimal.ToInt32(numericIdleTimeout.Value);
         }
         set
         {
            //if (value > numericIdleTimeout.Maximum) return;

            //numericIdleTimeout.Value = value;
         }
      }
      public IItemView SessionUsers
      {
         get
         {
            return null;// (IItemView)itemViewUsers["SessionUsers"];
         }
      }
      public bool SessionRemoveOnIdle
      {
         get
         {
            return false;// checkRemoveOnIdle.Checked;
         }
         set
         {
            //checkRemoveOnIdle.Checked = value;
            //numericIdleTimeout.Enabled = value;
         }
      }
      public IItemView AccountContacts
      {
         get
         {
            return null;// (IItemView)itemViewContacts["AccountContacts"];
         }
      }
      public int SessionParticipantsLimit
      {
         get
         {
            return 0;// decimal.ToInt32(numericUsersLimit.Value);
         }
         set
         {
            //numericUsersLimit.Value = value;
         }
      }
      public SessionSubtype SessionSubtype
      {
         get
         {
            //return !buttonIsTranslation.Checked && !buttonIsConference.Checked ? SessionSubtype.Personal :
            //         (buttonIsConference.Checked ? SessionSubtype.Conference : SessionSubtype.Translation);
            return SessionSubtype.Personal;
         }
         set
         {
            //switch (value)
            //{
            //   case SessionSubtype.Personal:
            //      buttonIsConference.Checked = false;
            //      buttonIsTranslation.Checked = false;
            //      break;
            //   case SessionSubtype.Conference:
            //      buttonIsConference.Checked = true;
            //      buttonIsTranslation.Checked = false;
            //      break;
            //   case SessionSubtype.Translation:
            //      buttonIsConference.Checked = false;
            //      buttonIsTranslation.Checked = true;
            //      break;
            //}
         }
      }
      public SessionVisibility SessionVisibility
      {
         get
         {
            return SessionVisibility.Private;// buttonVisibilityPublic.Checked ? SessionVisibility.Public : SessionVisibility.Private;
         }
         set
         {
            //buttonVisibilityPublic.Checked = value == SessionVisibility.Public;
            //buttonVisibilityPrivate.Checked = !buttonVisibilityPublic.Checked;

            //panelJoining.Enabled = !buttonVisibilityPrivate.Checked;
            //buttonAutoJoin.Checked = panelJoining.Enabled;
            //buttonAskJoin.Checked = panelJoining.Enabled;

            //SessionHostingType = buttonVisibilityPrivate.Checked ? SessionHostingType.Local : SessionHostingType.Default;
         }
      }
      public SessionJoinFilter SessionJoinFilter
      {
         get
         {
            //return buttonVisibilityPrivate.Checked ?
            //       SessionJoinFilter.Deny : (buttonAskJoin.Checked ?
            //       SessionJoinFilter.Ask : (checkRequireKey.Checked ?
            //       SessionJoinFilter.Keyed : SessionJoinFilter.Auto));
            return SessionJoinFilter.Deny;
         }
         set
         {
            //if (buttonVisibilityPrivate.Checked)
            //{
            //   buttonAskJoin.Checked = false;
            //   buttonAutoJoin.Checked = false;
            //   checkRequireKey.Checked = false;
            //}
            //else
            //{
            //   buttonAskJoin.Checked = value == SessionJoinFilter.Ask;
            //   buttonAutoJoin.Checked = value != SessionJoinFilter.Ask;
            //   checkRequireKey.Checked = value == SessionJoinFilter.Keyed;
            //}

            //checkRequireKey.Enabled = buttonAutoJoin.Checked;
            //editSessionKey.Enabled = checkRequireKey.Checked && checkRequireKey.Enabled;
         }
      }
      public SessionHostingType SessionHostingType
      {
         get
         {
            //return buttonDefaultServer.Checked ? SessionHostingType.Default : (buttonMyComputer.Checked ? SessionHostingType.Local : SessionHostingType.Custom);
            return SessionHostingType.None;
         }
         set
         {
            //buttonMyComputer.Checked = value == SessionHostingType.Local;
            //buttonCustomServer.Checked = value == SessionHostingType.Custom;
            //buttonDefaultServer.Checked = value == SessionHostingType.Default;

            //groupBoxHosting.Enabled = buttonVisibilityPublic.Checked;
            //editSessionMachine.Enabled = buttonCustomServer.Checked;
         }
      }

      public void ShowMainPage()
      {
         if (!panelMainPage.Visible)
         {
            panelMainPage.Visible = true;
            panelStartPage.Visible = false;
         }

         Refresh();
      }
      public void ShowStartPage(bool settings)
      {
         if (!panelStartPage.Visible)
         {
            panelStartPage.Visible = true;
            panelMainPage.Visible = false;
         }

         RefreshView();
      }
      public void ShowSessionParams(IMediaSession session, bool settings)
      {
         //
      }

      public virtual void ClearView()
      {
         //SessionUsers.Clear();
         //AccountContacts.Clear();
      }
      public virtual void RefreshView()
      {
         //if (FSession != null)
         //{
         //   SessionSubtype = Tag == null ? FSession.Subtype : SessionSubtype.Conference;

         //   SessionCaption = FSession.Caption;
         //   SessionVisibility = FSession.Visibility;
         //   SessionJoinFilter = FSession.JoinFilter;
         //   SessionIdleTimeout = FSession.IdleTimeout;
         //   SessionRemoveOnIdle = FSession.RemoveOnIdle;
         //   SessionParticipantsLimit = FSession.ParticipantsLimit;
         //   SessionSubject = Tag == null ? FSession.Subject : null;
         //   SessionInvitationText = Tag == null ? FSession.InvitationText : null;

         //   SessionUsers.Clear();

         //   foreach (User user in FSession.Participants)
         //   {
         //      SessionUsers.AddItem(user.Identifier, "",
         //                           user.Nickname,
         //                           (user is Account ?
         //                           "- " + Resources.S_You + " [" + user.Identifier + "]" :
         //                           "- " + Resources.S_Participant.ToLower()) +  Resources.S_joined_at +
         //                           FSession.JoinTimeStamps[user].ToShortTimeString(),
         //                           "Contact", user);
         //   }
         //   foreach (User user in FSession.Invitees)
         //   {
         //      SessionUsers.AddItem(user.Identifier, "", user.Nickname, "- Invited, waiting reply...", "Contact", user);
         //   }

         //   AccountContacts.CopyFrom(FCommunicator.MainWindow.GetContactsView(null));

         //   SessionUsers.SelectedItem = null;
         //   AccountContacts.SelectedItem = null;

         //   //linkLabelMainPage.Visible = FSession.State != SessionState.Closed;
         //   //buttonApply.Text = FSession.State == SessionState.Closed ? Resources.S_Start : Resources.S_Continue;

         //   ParamsEnabled = !FSession.IsPersonal && FSession.Account == FSession.SessionOwner;
         //}
         //else
         //{
         //   SessionCaption = null;
         //   SessionSubject = null;
         //   SessionIdleTimeout = 10;
         //   SessionRemoveOnIdle = true;
         //   SessionInvitationText = null;
         //   SessionParticipantsLimit = 10;
         //   SessionJoinFilter = SessionJoinFilter.Ask;
         //   SessionSubtype = SessionSubtype.Conference;
         //   SessionVisibility = SessionVisibility.Public;

         //   SessionUsers.Clear();
         //   AccountContacts.CopyFrom(FCommunicator.MainWindow.GetContactsView(null));

         //   //buttonApply.Text = Resources.S_Start;

         //   ParamsEnabled = true;
         //}
         Refresh();
      }
      public virtual void Translate(CultureInfo culture)
      {
         if (FResources == null) FResources = new ComponentResourceManager(GetType());
         if (Controls.Count > 0) Window.Translate(FResources, Controls[0], culture);
      }

      public event EventHandler ApplyPressed;

      #endregion

      #region SessionVisualizer Members

      private void buttonApply_Click(object sender, EventArgs e)
      {
         if (Session == null) // Create new session
         {
            MediaSession newSession = null;
            MediaSession oldSession = Tag as MediaSession; // session to add participants

            IEnumerable<User> invitees = SessionUsers.Items.Where(item => item[typeof(User)] is User).Select(item =>
                                         item[typeof(User)] as User).Where(user => user is Account == false);
            if (invitees.Count() > 0)
            {
               newSession = FCommunicator.CreateMediaSession(FCommunicator.SupportedMediaSessionTypes[oldSession == null ?
                                                             SessionType : oldSession.GetType()],
                                                             FCommunicator.CurrentAccount,
                                                             invitees,
                                                             SessionVisibility,
                                                             SessionHostingType,
                                                             null,
                                                             SessionSubtype) as MediaSession;
               if (newSession == null)
               {
                  MessageBox.Show(Resources.S_This_type_of_interaction_is_not_supported, Resources.S_Error, MessageBoxButtons.OK, MessageBoxIcon.Information);
                  return;
               }

               newSession.LogEvents = true;
               newSession.Subject = SessionSubject;
               newSession.JoinFilter = SessionJoinFilter;
               newSession.IdleTimeout = SessionIdleTimeout;
               newSession.RemoveOnIdle = SessionRemoveOnIdle;
               newSession.InvitationText = SessionInvitationText;
               newSession.ParticipantsLimit = SessionParticipantsLimit;
               newSession.Visualizer.SessionUsers.CopyFrom(SessionUsers);
               newSession.Visualizer.AccountContacts.CopyFrom(FCommunicator.MainWindow.GetContactsView(null));

               newSession.Start();

               MediaWindow.ActiveMediaSession = newSession;
            }
            else // Do nothing
            {
               MediaWindow.ActiveMediaSession = oldSession;
            }
         }
         else // Update session
         {
            MediaSession session = Session as MediaSession;

            if (session.SessionOwner == session.Account)
            {
               if (session.IsPersonal)
               {
                  if (session.State == SessionState.Closed) session.Start();
               }
               else
               {
                  session.Subject = SessionSubject;
                  session.JoinFilter = SessionJoinFilter;
                  session.IdleTimeout = SessionIdleTimeout;
                  session.RemoveOnIdle = SessionRemoveOnIdle;
                  session.InvitationText = SessionInvitationText;
                  session.ParticipantsLimit = SessionParticipantsLimit;

                  IEnumerable<User> invitees = SessionUsers.Items.Where(item => item[typeof(User)] is User).Select(item =>
                                               item[typeof(User)] as User).Where(user => session.NeedInvitation(user));

                  foreach (User user in invitees) session.Invitees.Add(user);

                  if (session.State == SessionState.Closed)
                  {
                     session.Start();
                  }
                  else
                  {
                     FCommunicator.SaveMediaSession(session, SaveMediaSessionActions.Update);

                     session.SendInvitation(null);
                  }
               }
            }
            session.Activate();
         }
         if (ApplyPressed != null) ApplyPressed(this, null);
      }
      private void linkLabelMainPage_Click(object sender, EventArgs e)
      {
         IMediaSession session = FSession != null ? FSession : Tag as IMediaSession;

         if (session != null)
         {
            MediaWindow.ActiveMediaSession = session;
            session.Visualizer.ShowMainPage();
         }
      }
      private void buttonBackControl_Click(object sender, EventArgs e)
      {
         ShowStartPage(true);
      }
      private void labelJoiningButton_Click(object sender, EventArgs e)
      {
         //ControlEffects.Slide(tabPageGeneral, panelJoining, panelJoiningHeaderBorder.Height - 8, labelJoiningButton, false, 0, SwitchSlideAction.Switch, null, null);
      }
      private void joinFilter_CheckedChanged(object sender, EventArgs e)
      {
         SessionJoinFilter = SessionJoinFilter;
      }
      private void accountContacts_KeyDown(object sender, KeyEventArgs e)
      {
         if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Space)
         {
            buttonAddParticipants_Click(sender, e);
         }
      }
      private void selectServer_CheckedChanged(object sender, EventArgs e)
      {
         SessionHostingType = SessionHostingType;
      }
      private void removeOnIdle_CheckedChanged(object sender, EventArgs e)
      {
         SessionRemoveOnIdle = SessionRemoveOnIdle;
      }
      private void buttonAddParticipants_Click(object sender, EventArgs e)
      {
         if (AccountContacts.SelectedItem != null) SessionUsers.CopyItem(AccountContacts.SelectedItem, null, DropResults.AppendChild | DropResults.DeepCopy);
         ((Control)SessionUsers).Select();
      }
      private void buttonRemoveParticipants_Click(object sender, EventArgs e)
      {
         if (SessionUsers.SelectedItem != null) SessionUsers.RemoveItem(SessionUsers.SelectedItem);
      }
      private void sessionVisibility_CheckedChanged(object sender, EventArgs e)
      {
         SessionVisibility = SessionVisibility;
      }
      private void sessionUsers_ItemRemoved(object sender, ItemViewBasicEventArgs e)
      {
         if (Session != null)
         {
            User user = e.Item[typeof(User)] as User;
            if (Session.IsInvited(user) || Session.IsParticipant(user)) Session.RemoveParticipant(user);

            FCommunicator.SaveMediaSession(Session, SaveMediaSessionActions.RemoveParticipant, user);
         }
      }
      private void sessionUsers_ItemAdding(object sender, ItemViewCancelEventArgs e)
      {
         if (SessionUsers[e.Item.Name] != null)
         {
            e.Cancel = true;
            SessionUsers.SelectedItem = SessionUsers[e.Item.Name];
         }
         else
         {
            e.Item.ImageName = "Contact";
         }
      }
      private void sessionUsers_ItemRemoving(object sender, ItemViewRemovingEventArgs e)
      {
         if (e.Item[typeof(User)] is Account)
         {
            e.Cancel = true;
            MessageBox.Show(Resources.S_You_can_not_remove_yourself_from_the_session, Resources.S_Info, MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
         }
      }
      private void users_ItemContextMenu(object sender, ItemViewBasicEventArgs e)
      {
         FCommunicator.ShowUserMenu(e.Item[typeof(User)] as User);
      }
      private void communicator_StylesChanged(object sender, PropertyChangedEventArgs e)
      {
         if (e.PropertyName == "ColorTheme") ColorTheme = FCommunicator.ColorTheme;
         else if (e.PropertyName == "RenderMode") RenderMode = FCommunicator.RenderMode;
      }
      
      private void view_HeaderPaint(object sender, PaintEventArgs e)
      {
         // Check on null to allow designer of child controls to draw them
         if (FCommunicator != null) FCommunicator.DrawTheme(ColorTheme, e.Graphics, (sender as Control).ClientRectangle, ColorThemeObject.Pattern);
      }
      private void panelParamsBody_Paint(object sender, PaintEventArgs e)
      {
         // Check on null to allow designer of child controls to draw them
         if (FCommunicator != null) FCommunicator.DrawTheme(ColorTheme, e.Graphics, (sender as Control).ClientRectangle, ColorThemeObject.Area);
      }
      private void panelParamsHeader_Paint(object sender, PaintEventArgs e)
      {
         // Check on null to allow designer of child controls to draw them
         if (FCommunicator != null) FCommunicator.DrawTheme(ColorTheme, e.Graphics, (sender as Control).ClientRectangle, ColorThemeObject.PanelH);
      }

      #endregion
   }

   public abstract class MediaSession : CommunicationEventHanldlerObject, IMediaSession
   {
      #region MediaSession Data

      protected object FTag;
      protected string FName;
      protected string FGsid;
      protected string FSubject;
      protected string FJoinKey;
      protected int FIdleTimeout;
      protected Account FAccount;
      protected User FSessionOwner;
      protected bool FRemoveOnIdle;
      protected bool FIsEstablished;
      protected SessionState FState;
      protected int FParticipantsLimit;
      protected string FInvitationText;
      protected SessionSubtype FSubtype;
      protected SessionJoinFilter FJoinFilter;
      protected SessionVisibility FVisibility;
      protected ServiceSession FHostingSession;
      protected ISessionVisualizer FVisualizer;
      protected IBaseCommunicator FCommunicator;
      protected ServiceMessage FLastIncomingMessage;
      protected ServiceMessage FLastOutgoingMessage;

      protected Collection<User> FInvitees = new Collection<User>();
      protected Collection<User> FParticipants = new Collection<User>();
      protected Collection<User> FBlockedUsers = new Collection<User>();
      protected Collection<User> FSelectedUsers = new Collection<User>();
      protected Dictionary<User, DateTime> FJoinTimeStamps = new Dictionary<User, DateTime>();

      #endregion

      #region MediaSession Initializers

      public MediaSession(Account account, XElement xData, IEnumerable<User> users)
      {
         FSubject = "";
         FAccount = account;
         FInvitationText = "";
         FState = SessionState.Ready;
         FSubtype = SessionSubtype.Conference;
         FCommunicator = account.ServiceDriver.Communicator;

         FParticipants.Add(account);
         FJoinTimeStamps[account] = DateTime.Now;
         XObject = xData;
         FSessionOwner = FParticipants[1];
         if (users != null) foreach (User user in users) FInvitees.Add(user);
      }

      public MediaSession(Account account, User owner, IEnumerable<User> users, ServiceSession hostingSession,
                          SessionVisibility visibility, SessionSubtype subtype)
      {
         FAccount = account;
         FState = SessionState.Closed;
         FSubtype = SessionSubtype.Conference;
         FCommunicator = account.ServiceDriver.Communicator;

         Gsid = null; // Generate GSID
         FSubject = "";
         FSubtype = subtype;
         FInvitationText = "";
         FVisibility = visibility;
         FHostingSession = hostingSession;

         FSessionOwner = owner;
         FParticipants.Add(account);
         FJoinTimeStamps[account] = DateTime.Now;
         if (owner is Contact) AddParticipant(owner, false);
         if (users != null) foreach (User user in users) FInvitees.Add(user);
      }

      public virtual void CleanupMedia()
      {
         if (FVisualizer != null) (FVisualizer as UserControl).Dispose();

         FVisualizer = null;
      }

      public abstract void InitializeMedia();

      #endregion

      #region IMediaSession Properties

      public object Tag
      {
         get
         {
            return FTag;
         }
         set
         {
            FTag = value;
         }
      }
      public string Name
      {
         get
         {
            return FName;
         }
         set
         {
            FName = value;
         }
      }
      public string Gsid
      {
         get
         {
            return FGsid == null ? "" : FGsid;
         }
         set
         {
            FGsid = value != null ? value : Guid.NewGuid().ToString();
         }
      }
      public bool IsActive
      {
         get
         {
            return FState != SessionState.Closed;
         }
      }
      public string JoinKey
      {
         get
         {
            return FJoinKey;
         }
         set
         {
            JoinKey = value;
         }
      }
      public string Subject
      {
         get
         {
            return FSubject;
         }
         set
         {
            if (FSubject == value) return;

            if (FAccount != FSessionOwner) throw new Exception("Subject can be changed only by session owner.");

            FSubject = value;

            FireParamsChangedEvent("Subject");
         }
      }
      public int IdleTimeout
      {
         get
         {
            return FIdleTimeout;
         }
         set
         {
            if (FAccount != FSessionOwner) throw new Exception("IdleTimeout can be changed only by session owner.");

            if (FIdleTimeout == value) return;

            FIdleTimeout = value;
            FireParamsChangedEvent("IdleTimeout");
         }
      }
      public bool IsPersonal
      {
         get
         {
            return FSubtype == SessionSubtype.Personal;
         }
      }
      public Account Account
      {
         get
         {
            return FAccount;
         }
         set
         {
            FAccount = value;
         }
      }
      public XElement XObject
      {
         get
         {
            XElement xSession = new XElement("XSession");

            xSession.SetAttributeValue("Gsid", Gsid);
            xSession.SetAttributeValue("Subject", Subject);
            xSession.SetAttributeValue("Subtype", Subtype);
            xSession.SetAttributeValue("Type", GetType().Name);
            xSession.SetAttributeValue("Visibility", Visibility);
            xSession.SetAttributeValue("JoinFilter", JoinFilter);
            xSession.SetAttributeValue("IdleTimeout", IdleTimeout);
            xSession.SetAttributeValue("RemoveOnIdle", RemoveOnIdle);
            xSession.SetAttributeValue("InvitationText", InvitationText);
            xSession.SetAttributeValue("ParticipantsLimit", ParticipantsLimit);
            //if (HostingSession != null) x.Add(HostingSession.ToXml());
            xSession.Add(new XElement("Participants", FParticipants.Select(user => new XElement("User", user))));
            xSession.Add(new XElement("Invitees", FInvitees.Select(user => new XElement("User", user))));

            return xSession;
         }
         set
         {
            XAttribute gsid = value.Attribute("Gsid");
            XAttribute subject = value.Attribute("Subject");
            XAttribute subtype = value.Attribute("Subtype");
            XAttribute visibility = value.Attribute("Visibility");
            XAttribute joinFilter = value.Attribute("JoinFilter");
            XAttribute idleTimeout = value.Attribute("IdleTimeout");
            XAttribute removeOnIdle = value.Attribute("RemoveOnIdle");
            XAttribute invitationText = value.Attribute("InvitationText");
            XAttribute participantsLimit = value.Attribute("ParticipantsLimit");

            if (gsid != null) FGsid = (string)gsid;
            if (subject != null) FSubject = (string)subject;
            if (idleTimeout != null) FIdleTimeout = (int)idleTimeout;
            if (removeOnIdle != null) FRemoveOnIdle = (bool)removeOnIdle;
            if (invitationText != null) FInvitationText = (string)invitationText;
            if (participantsLimit != null) FParticipantsLimit = (int)participantsLimit;
            if (subtype != null) FSubtype = (SessionSubtype)Enum.Parse(typeof(SessionSubtype), (string)subtype);
            if (visibility != null) FVisibility = (SessionVisibility)Enum.Parse(typeof(SessionVisibility), (string)visibility);
            if (joinFilter != null) FJoinFilter = (SessionJoinFilter)Enum.Parse(typeof(SessionJoinFilter), (string)joinFilter);
            //if (value.Element("{CoreTypes}ServiceSession") != null) FHostingSession = (ServiceSession)ObjectExtension.ParseXml(typeof(ServiceSession), value.Element("{CoreTypes}ServiceSession").ToString());

            foreach (User user in value.Element("Participants").Elements().Select(x => new User(x.Value)))
            {
               if (user.Identifier == Account.Identifier) continue;

               Contact contact = Account.GetContact(user.Identifier);

               AddParticipant(contact == null ? user : contact, true);
            }
            foreach (User user in value.Element("Invitees").Elements().Select(x => new User(x.Value)))
            {
               if (user.Identifier == Account.Identifier) continue;

               Contact contact = Account.GetContact(user.Identifier);

               Invitees.Add(contact == null ? user : contact);
            }
         }
      }
      public User SessionOwner
      {
         get
         {
            return FSessionOwner;
         }
      }
      public bool RemoveOnIdle
      {
         get
         {
            return FRemoveOnIdle;
         }
         set
         {
            if (FAccount != FSessionOwner) throw new Exception("RemoveOnIdle can be changed only by session owner.");

            if (FRemoveOnIdle == value) return;

            FRemoveOnIdle = value;
            FireParamsChangedEvent("RemoveOnIdle");
         }
      }
      public bool IsConference
      {
         get
         {
            return FSubtype == SessionSubtype.Conference;
         }
      }
      public bool IsEstablished
      {
         get { return FIsEstablished; }
      }
      public SessionState State
      {
         get
         {
            return FState;
         }
         private set
         {
            if (FState == value) return;

            FState = value;

            FireParamsChangedEvent("State");
         }
      }
      public Contact Interlocutor
      {
         get
         {
            return FParticipants.Count > 1 ? (Contact)FParticipants[1] : null;
         }
      }
      public int ParticipantsLimit
      {
         get
         {
            return FParticipantsLimit;
         }
         set
         {
            if (FAccount != FSessionOwner) throw new Exception("This property can be changed only by session owner.");

            if (FParticipantsLimit == value) return;

            if (value < FParticipants.Count - 1)
            {
               // code removing extra users here
            }
            else if (value > FParticipants.Count - 1)
            {
               FParticipantsLimit = value;
            }
            FireParamsChangedEvent("ParticipantsLimit");
         }
      }
      public string InvitationText
      {
         get
         {
            return FInvitationText;
         }
         set
         {
            if (FAccount != FSessionOwner) throw new Exception("InvitationText can be changed only by session owner.");

            if (FInvitationText == value) return;

            FInvitationText = value;
            FireParamsChangedEvent("InvitationText");
         }
      }
      public string RecipientsNames
      {
         get
         {
            return StringExt.Join(Recipients.Union(Invitees).Select(user => user.CustomName), ", ");
         }
      }
      public virtual string Caption
      {
         get
         {
            string names = RecipientsNames;
            if (names.Length == 0) names = "No Recipients";
            string typeTag = Subtype.ToString();
            string subject = string.IsNullOrEmpty(FSubject) ? "" : FSubject + " - ";

            return subject + names + typeTag;
         }
      }
      public SessionSubtype Subtype
      {
         get
         {
            return FSubtype;
         }
         protected set
         {
            if (FAccount != FSessionOwner) throw new Exception("This property can be changed only by session owner.");

            if (FSubtype == value) return;

            FSubtype = value;

            FireParamsChangedEvent("Subtype");
         }
      }
      public IList<User> Recipients
      {
         get
         {
            if (FSelectedUsers.Count > 0)
            {
               return FSelectedUsers.ToList();
            }
            else
            {
               return FParticipants.Where(user => user is Account == false).ToList();
            }
         }
      }
      public bool IsVisibleAndActive
      {
         get
         {
            return Visualizer != null &&
                   Visualizer.MediaWindow != null &&
                   Visualizer.MediaWindow.IsActive &&
                   Visualizer.MediaWindow.ActiveMediaSession == this;
         }
      }
      public IList<User> Participants
      {
         get
         {
            return FParticipants.ToList();
         }
      }
      public Collection<User> Invitees
      {
         get
         {
            return FInvitees;
         }
      }
      public SessionVisibility Visibility
      {
         get
         {
            return FVisibility;
         }
         set
         {
            if (FAccount != FSessionOwner) throw new Exception("Visibility can be changed only by session owner.");

            if (IsActive || FVisibility == value) return;

            FVisibility = value;

            FireParamsChangedEvent("Visibility");
         }
      }
      public SessionJoinFilter JoinFilter
      {
         get
         {
            return FJoinFilter;
         }
         set
         {
            if (FAccount != FSessionOwner) throw new Exception("JoinFilter can be changed only by session owner.");

            if (FJoinFilter == value) return;

            FJoinFilter = value;
            FireParamsChangedEvent("JoinFilter");
         }
      }
      public ISessionVisualizer Visualizer
      {
         get
         {
            return FVisualizer;
         }
      }
      public ServiceSession HostingSession
      {
         get
         {
            return FHostingSession;
         }
         set
         {
            if (IsActive) return;

            FHostingSession = value;
         }
      }
      public IBaseCommunicator Communicator
      {
         get { return FCommunicator; }
      }
      public ServiceMessage LastOutgoingMessage
      {
         get
         {
            return FLastOutgoingMessage;
         }
      }
      public ServiceMessage LastIncomingMessage
      {
         get
         {
            return FLastIncomingMessage;
         }
      }
      internal Dictionary<User, DateTime> JoinTimeStamps
      {
         get
         {
            return FJoinTimeStamps;
         }
      }

      #endregion

      #region IMediaSession Members

      public void Show()
      {
         if (FVisualizer == null) InitializeMedia();

         FVisualizer.Visualize();
      }
      public void Hide()
      {
         if (FVisualizer != null) FVisualizer.Conceal();
      }
      public void Start()
      {
         if (SessionOwner != Account) throw new Exception("Session can be started by the owner only.");

         if (FState != SessionState.Closed) throw new Exception("This session already started.");

         if (Visualizer == null) InitializeMedia();

         if (IsPersonal)
         {
            State = SessionState.Ready;
         }
         else
         {
            State = SessionState.Establishing;

            FCommunicator.SaveMediaSession(this, SaveMediaSessionActions.Update);
         }
      }
      public void Close()
      {
         CancelEventArgs args = null;

         if (Closing != null) Closing(this, args = new CancelEventArgs());

         if (args != null && args.Cancel) return;

         foreach (User user in Participants) if (user is Contact) (user as Contact).MediaSessions.Remove(this);

         FState = SessionState.Closed;

         if (Closed != null) Closed(this, null);

         CleanupMedia();

         GC.Collect(GC.GetGeneration(this));
      }
      public void Shutdown()
      {
         //throw new Exception("The method or operation is not implemented.");
      }
      public void Activate()
      {
         Show();

         FireActivatedEvent();
      }
      public void SelectAll()
      {
         throw new Exception("The method or operation is not implemented.");
      }
      public void Deselect(User user)
      {
         FSelectedUsers.Remove(user);
      }
      public void BlockUser(User user)
      {
         if (IsParticipant(user) && !FBlockedUsers.Contains(user))
         {
            FBlockedUsers.Add(user);

            if (ParticipantsChanged != null) ParticipantsChanged(this, new ParticipantsChangedEventArgs(user, Account, false, true, true));
         }
      }
      public bool IsInvited(User user)
      {
         return FInvitees.Contains(user);
      }
      public bool IsSelected(User user)
      {
         if (user == null) return FSelectedUsers.Count != 0;

         return FSelectedUsers.Contains(user);
      }
      public void UnblockUser(User user)
      {
         if (FBlockedUsers.Remove(user) && ParticipantsChanged != null) ParticipantsChanged(this, new ParticipantsChangedEventArgs(user, Account, false, false, false));
      }
      public void RemoveAllParticipants()
      {
         foreach (User user in Participants) if (user is Contact) RemoveParticipant((Contact)user);
      }
      public bool IsParticipant(User user)
      {
         //return FParticipants.Any(user => user.Identifier == id);
         return FParticipants.Contains(user);
      }
      public bool NeedInvitation(User user)
      {
         return !(IsParticipant(user) || IsInvited(user));
      }
      public User GetParticipant(string id)
      {
         return FParticipants.FirstOrDefault(user => user.Identifier == id);
      }
      public void RemoveParticipant(User user)
      {
         if (IsParticipant(user))
         {
            FParticipants.Remove(user);
            if (!IsConference) Deselect(user);
            if (user is Contact) (user as Contact).MediaSessions.Remove(this);

            if (ParticipantsChanged != null) ParticipantsChanged(this, new ParticipantsChangedEventArgs(user, Account, true, false, false));

            if (IsPersonal) Close();
         }
         else if (IsInvited(user))
         {
            FInvitees.Remove(user);

            if (ParticipantsChanged != null) ParticipantsChanged(this, new ParticipantsChangedEventArgs(user, Account, true, false, false));
         }
      }
      public void Select(User user, bool exclusive)
      {
         if (user == null)
         {
            FSelectedUsers.Clear();
            return;
         }

         if (exclusive) FSelectedUsers.Clear();

         if (!IsParticipant(user)) return;

         if (!IsSelected(user)) FSelectedUsers.Add(user);
      }
      public bool AddParticipant(User user, bool show)
      {
         if (IsParticipant(user)) return false;

         FParticipants.Add(user);
         FInvitees.Remove(user);
         if (!IsConference) Select(user, false);
         if (user is Contact) (user as Contact).MediaSessions.Add(this);
         FireParticipantsChangedEvent(new ParticipantsChangedEventArgs(user, Account, show));
         FJoinTimeStamps[user] = DateTime.Now;

         return true;
      }

      public override string ToString()
      {
         return Caption + " {" + Gsid + "}";
      }

      #endregion

      #region IMediaSession Events

      public event EventHandler Closed;
      public event EventHandler Activated;
      public event EventHandler<CancelEventArgs> Closing;
      public event PropertyChangedEventHandler ParamsChanged;
      public event EventHandler<ParticipantsChangedEventArgs> ParticipantsChanged;

      public void FireActivatedEvent()
      {
         if (Activated != null) Activated(this, null);
      }
      public void FireParamsChangedEvent(string name)
      {
         if (ParamsChanged != null) ParamsChanged(this, new PropertyChangedEventArgs(name));
      }
      public void FireParticipantsChangedEvent(ParticipantsChangedEventArgs args)
      {
         if (ParticipantsChanged != null) ParticipantsChanged(this, args);
      }

      #endregion

      #region CommunicationEventHanldlerObject Members

      public override void OnSaveMediaSessionState(object sender, SaveMediaSessionEventArgs e)
      {
         if (e.Error != null)
         {
            FCommunicator.ShowError("Session update failed.", e.Error);
         }
         else
         {
            //
         }

         base.OnSaveMediaSessionState(this, e);
      }
      public override void OnSendInvitationState(object sender, MessagingOperationEventArgs e)
      {
         if (e.Error != null)
         {
            State = SessionState.Closed;
         }
         else
         {
            State = SessionState.Establishing;

            if (e.State == OperationState.DataSending)
            {
               FLastOutgoingMessage = e.EventMessage;
            }
         }

         base.OnSendInvitationState(this, e);
      }
      public override void OnSendChatMessageState(object sender, MessagingOperationEventArgs e)
      {
         if (e.Error != null)
         {
            State = SessionState.Ready;
         }
         else if (e.State == OperationState.DataSending)
         {
            FLastOutgoingMessage = e.EventMessage;

            State = SessionState.Sending;
         }
         else if (e.State == OperationState.DataSent)
         {
            State = e.EventMessage.NoAcknowledges ? SessionState.Ready : SessionState.Waiting;
         }
         else if (e.State == OperationState.Completed)
         {
            State = SessionState.Ready;
         }

         base.OnSendChatMessageState(this, e);
      }
      public override void OnUpdateChatMessageState(object sender, MessagingOperationEventArgs e)
      {
         base.OnUpdateChatMessageState(this, e);
      }

      public override void OnPresenceNotified(object sender, MessagingOperationEventArgs e)
      {
         if (LogEvents) e.EventMessage.MediaSession = this;

         base.OnPresenceNotified(this, e);
      }
      public override void OnInvitationReceived(object sender, MessagingOperationEventArgs e)
      {
         if (LogEvents) e.EventMessage.MediaSession = this;

         FLastIncomingMessage = e.EventMessage;

         base.OnInvitationReceived(this, e);
      }
      public override void OnChatMessageReceived(object sender, MessagingOperationEventArgs e)
      {
         if (LogEvents) e.EventMessage.MediaSession = this;

         FLastIncomingMessage = e.EventMessage;

         base.OnChatMessageReceived(this, e);
      }
      public override void OnAcknowledgeReceived(object sender, MessagingOperationEventArgs e)
      {
         if (e.Error != null)
         {
            State = SessionState.Ready;
         }
         else if (e.State == OperationState.Callback)
         {
            State = e.EventMessage.NoAcknowledges ? SessionState.Ready : SessionState.Waiting;
         }
         else if (e.State == OperationState.Completed || e.RequestMessage.IsFullyAcknowledged)
         {
            State = SessionState.Ready;
         }

         base.OnAcknowledgeReceived(this, e);
      }
      public override void OnMediaSessionUpdated(object sender, MediaSessionUpdateEventArgs e)
      {
         base.OnMediaSessionUpdated(this, e);
      }
      public override void OnInvitationReplyReceived(object sender, MessagingOperationEventArgs e)
      {
         if (e.ReplyMessage.Result == 1) AddParticipant(e.ReplyMessage.Sender, true);

         if ((e.RequestMessage as SessionInvitation).ReplyCount == e.RequestMessage.Recipients.Count())
         {
            State = SessionState.Ready;
         }

         base.OnInvitationReplyReceived(this, e);
      }
      public override void OnChatMessageUpdateReceived(object sender, MessagingOperationEventArgs e)
      {
         base.OnChatMessageUpdateReceived(this, e);
      }

      #endregion

      #region ICommunicationServiceObject Members

      public int ListenPort
      {
         get
         {
            return Account.ServiceDriver.ListenPort;
         }
      }
      public ServiceInfo ServiceInfo
      {
         get { return null; }
      }

      public void Logoff(Account account)
      {
         throw new NotImplementedException("MediaSession.Logoff");
      }
      public void DropAccount(Account account)
      {
         throw new NotImplementedException();
      }
      public void SyncContacts(Account account)
      {
         throw new NotImplementedException();
      }
      public void LoadAccountData(Account account)
      {
         throw new NotImplementedException();
      }
      public void CreateAccount(RegistrationInfo info)
      {
         throw new NotImplementedException();
      }
      public void SendChatMessage(ChatMessage message)
      {
         if (FLastOutgoingMessage == null) message.Status = Account.Status;

         Account.ServiceDriver.SendChatMessage(message);
      }
      public void UpdateMessage(ServiceMessage message)
      {
         throw new NotImplementedException();
      }
      public void Logon(Account account, Status status)
      {
         throw new NotImplementedException();
      }
      public void SeekUsers(string query, IWindow sender)
      {
         throw new NotImplementedException();
      }
      public void SendAcknowledge(ServiceMessage message)
      {
         throw new NotImplementedException();
      }
      public void SendInvitation(SessionInvitation message)
      {
         if (FInvitees.Count == 0) return;

         if (SessionOwner != Account) throw new Exception("Session can be started by the owner only.");

         if (message == null) message = new SessionInvitation(this);

         Account.ServiceDriver.SendInvitation(message);
      }
      public void RequestUserInfo(User user, bool shortInfo)
      {
         throw new NotImplementedException();
      }
      public void SendInvitationReply(ServiceMessage message)
      {
         if (SessionOwner == FAccount) return;

         FAccount.ServiceDriver.SendInvitationReply(message);
      }
      public void NotifyPresence(Account account, User user, Status status)
      {
         throw new NotImplementedException();
      }
      public void ChangePrivateData(Account account, string password, string mail)
      {
         throw new NotImplementedException();
      }
      public void SaveAccountData(Account account, SaveAccountActions actions, params object[] data)
      {
         throw new NotImplementedException();
      }
      public void SaveMediaSession(IMediaSession session, SaveMediaSessionActions actions, params object[] data)
      {
         if (SessionOwner != Account) throw new Exception("Session can be updated by the owner only.");

         FAccount.ServiceDriver.SaveMediaSession(this, actions, data);
      }
      public void SetPermissions(Account account, object target, PolicyRule message, PolicyRule invitation, PolicyRule visibility)
      {
         throw new NotImplementedException();
      }

      public bool IsConnected(Account account)
      {
         return false;
      }
      public bool IsLogonInProgress(Account account)
      {
         return false;
      }
      public ushort AddListener(string name, ushort port)
      {
         return Account.ServiceDriver.AddListener(name, port);
      }

      #endregion
   }
}